//! 针对加密的 QRC （此处定义为 Encrypted QRC (EQRC)）格式的解密模块
//!
//! 参考自 <https://github.com/WXRIW/Lyricify-Lyrics-Helper/blob/07d495c3b36ef24dbe5bc29c261e77bd16ff15d0/Lyricify.Lyrics.Helper/Decrypter/Qrc/Helper.cs#L49>
use std::sync::LazyLock;

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;
pub(super) mod qdec;

const DEC_KEY: &[u8; 24] = b"!@#)(*$%123ZXC!@!@#)(NHL";

static CIPHER: LazyLock<qdec::TripleQDES> = LazyLock::new(|| qdec::TripleQDES::new(DEC_KEY, true));

fn decode_hex(s: &str) -> Vec<u8> {
    if s.len() % 2 == 0 {
        (0..s.len())
            .step_by(2)
            .filter_map(|i| s.get(i..i + 2).map(|sub| u8::from_str_radix(sub, 16).ok()))
            .flatten()
            .collect()
    } else {
        vec![]
    }
}

pub fn decrypt_qrc_raw(data: &mut [u8]) -> String {
    for chunk in data.chunks_exact_mut(8) {
        let chunk = chunk.try_into().unwrap();
        CIPHER.crypt_inplace(chunk);
    }

    // 考虑到 WASM 环境不适合用 rayon 并行处理，暂时注释掉并行处理的代码，理论上启用后能将解密速度提升至少3倍
    // use rayon::prelude::*;
    // data.par_chunks_exact(8)
    //     .for_each(|chunk| {
    //         let mut chunk = chunk.try_into().unwrap();
    //         CIPHER.crypt_inplace(&mut chunk);
    //     });

    let decompressed = miniz_oxide::inflate::decompress_to_vec_zlib(data).unwrap_or_default();

    String::from_utf8_lossy(&decompressed).to_string()
}

#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(js_name = "decryptQrcHex", skip_typescript)]
pub fn decrypt_qrc_hex_js(hex_data: &str) -> String {
    decrypt_qrc_hex(hex_data)
}

pub fn decrypt_qrc_hex(hex_data: &str) -> String {
    let mut hex_data = decode_hex(hex_data);
    decrypt_qrc_raw(&mut hex_data)
}

#[test]
fn test_decrypt_qrc_hex() {
    let hex_data = "76782DD2D2D02305BAD47017F2618CC5613974810544E844BE4D1B83CFB246AD03E593EF0A5946BC253527D85D29AA319B8ED03CFE295021A5069D9E31E738651CBA39A6B040538CC1DA3A5F4314109F3669F6E4999398B540BC91B0ED81BCB2BC59D6AD4DC6F968DDEF2BA95B1AF8CDE8D28C39B73C26E175CCD8CD0EC4F4D3D2BFD6DB8275668FA3AFCA4B468FA626AFAB16754CD8D47448A7F643E21BF0822CB3EF9EE01F64B5EC9FC4CF5AC013FE31BDE0C654B0D26C8D2DC44E07A45FDF07ED1DFA5CB5D5B03DB41F9E32DB218B2F7F09286B4AAFF42A86712D4B98BEDDD0D57227002EA453C0F1DEF24762EFBF4E398FA1D9472750CF7B469DDAF2B8B108A0D57C250FDA037FEC72C21DC70FC5C2B32DE3719BC8F75DB09C0CDB88C57DC410A728540629F4FA3A2A01DA439151C408250E96DEEDC0B7ED4D3B75BD4ABC5BC2917408B612ABD311967790A4D39BE4563E385AA1AFE23C762F68E629BC69B906AC4A6E9B732103132A3A5319C1DE2C5C3AAE7EF722080A23FEC4EB06134C926A97FC6C48B892555731CF6BADFF7AFDDD8DA1BFA5B4DD41D4D5830C38B54C7E75AC66C3B7C3367CAD9FA676BB25B142D5399909C77A48945808214DFAA9929CEB44DB6FAA0DA1186D5745A8356A94696BB83B344C9A284019F2336BC09D5A77E8C38A60A6D2236E86C3D2EDA90C2B7E91E6660BEB119B6144C8E56D020FD866263520CA4C10DC4169B3BF694FD86167294431041E91E74EECC02CF04C5E7AC6A700D9294E98EDB0B68DA234FF4C23AFEB67E6D9CF731733CCD7E2EAC70F0367C67CAF0EE95ABA6B0D8F623E98E78EA4A1F882900E63FA5436864E69F00BABD1ED9010D59BE88C40118154DCE5B8D6F5D8E7D2FB06563400ABCE4FF946557BC00B22C4C7593F328A5FDCE442A05F438015D172C0E9F56B8C8D97DEAF1DDD77518CCCB26865EFC23D48AF3CF828F5735EBB96F3FEFB526F6B83916958CAFAD4DCFFF40C3A5F2682B1D4D24033D5A88FB5E051D98540581B61B4642D9CD45C1583726ABE3FC8E160BABE053FC03C5E07E95A6ECB05BDD30DE7046CFC240FC38578CBD132BFD196F3E89203555CB8FC3870A3633D9728775BCACB9F5502E13349CFE57450919990EC9403B52BDD708DC8E064CEE9BE67EE9D07EE61E5650E721473C42875B80004B86750176B4A0683C4B240640B63AB583FEE83A2B9EA32309F6933AEA1E78975B14552AC2421F15F44F0860BAE515BE87EFBCFD27DB1ACD14EC835CAB8A27AA6C3F119BC2524AA6849D8E943D887901C652822B594134DDD019CD176B5200BB80BD7E45C1B30ACF59150F062D114D9FEB446508467F6F8906CBF30ACC8A2FB809D26BD2976A33162C0C9E23DB77F53D8B645D03129631CCA59A98BEE0467E2E9954D289CA4675776D57DC90FE494482DDD73376ABA47611E23FA72106C4320510041ECEA9120F0CAEC77F7BE1C4EF3E3CBA513F11AAB1E820E46CC7AD1A06928075EC9CDB1A4785883F21B67D6CD21B39177A7338B24A689C3690418969220794A7F8715724E920A15E2FD088D0DF6151F07916F2883AE3276AC2CCCAEA6B2B1C9654B78B8AB444DBF5A37B2FC19BFF8EADF2AE694F63836C1B00BF4A8774E45824BBF44D5C4ED2C4F6431F5D8856424525F83BF5B77DA31E6DD5C475CB860D0A8BB54D747E08448242647B236D9E87D7CAD201E22EA1BEBBE9294B5960A3E75E9847A8F4845708F5917214C2E008451C0AAA75535AD7DD59234ACDD129146A5258FEF477B730582213EF185621F0058243ACF0BD4B7138F553184ED3CEC676091E7EAE831E8C95A65D47B5A37A928C9FABEA9FA6A4F97CEBEF5066C9F418A9A31F075B4612FF820C901FACA543160DFD029B02D59EC48C771F7D685BDA7039EF02DA9198678C3E06BEC0A7672D275115C44991646035EAB4C2E4B5323B7657AC50E711D62AB3EA5ECD78B60158EAB0C164C82D314E26CD6469AB0BEE032F0FBBE3A3CD5F85497A7B193D05182EAE23AB515253B102CA7F2F0DF9DE21BF25AF34DB0772C427F03EC5067904D6D77A812B6F6A5C1F2248F362C41E419CB55C536246E9E49E702CC3EDAE7D70D683B05E01749E9B2B16C157A97CA9298CA2B55791093E5250DA6F36DBCD7C573A8E58E52ED11A12B38BD4512DBAF636D9241D6FA26BB853D259B8C4C8A41AB1603F1F367D4D7E4DEED339B1F6FE9C47A485602772B15BAE25EBED881A4ECF28327DC920C30B749527A0734482CF39851FFC9D331275262FC83E1492858AE4677A8CB80CD757BAEC25A97ED834142AF52F7289D34FE730B43C2A28CA9D93B7BFCA8FB79B665035188B07952957BE2E66BB85A9A319E0D27B3D0E9AE726213A6FC1F5B82D237669B0852DAA198CC38BFE75B1FD6B130546BFB2EB6172B4222C37B86B7427764A7C945868670186BE7B9A32C516B3DCF7432F405A70B90EE87FD1658ABD50D1037BCC8DF286D6DDC39B4E9228AF969057610722DDBAE559ACEFFC6B6CC00F503A27BCDF442EF77D79BFCC92101EA986866EEBFF3BA6C44ECFC0AA2BC1A14E20EBA58DC0CBBA3C1545D49526267865321FB1A07448C7E39A40E1E6BC5FB72860CD8B12BE10EAEBEBF6F0133FDA4CA2195E162D9367ED713F43851F8647D1665938D1B6FD4BF76E6955DDEDB2149C4127BF0BDD7CDEE2EAAF023432D33EB023D60E088CDB013F253FC6A1AC76DAD19948A4DE7C9FEB98941809B0F6183A78DCAFC8DED2635C441B415415FBEF121282756966A2C157C20B5689D139DF8DD367B68ED66E4C96726B14ABC98FA8E21F5BB30188BAEEC9947F0F072028AAEAA25DB5C0F4A4F4A922464A8422A9F167B5C5CD32CC2008D7ED4E005DC0D8032433088A019920BEAAF86E606A8256FD8170B2DFEFB5ECF8EDFC5B5A54F3391357025403828CAED8086807F140CC59A1B0EABE9B74E4579CEFEBD56881D4BAF5B1E53E070180011E583C22195128A0ABC8B2D95981370E298EA39C1A6B83A3D21EBBFFE4EBAB8DE595771B60FDB8704106112B26116E6C7F21A4551C172AB13812AE498B85B9F32CA9D6AE5DC9CE73331209D0C5E159296508089B1628867CB2882DE7E49680F17F57829478C682DACEE0C70B95E9BFCC95934F88DE5861FE5684E3D2189C8E71E5EC20A20BEF3755B8F5FC8D910B80FA9EF1393DED8289AD25C6B4EFC3B2DDB270BB16A26C92EF920DF2AF4F95B888D9B8597629B058BCC0CB87C3994B6BB2705B0072D6B8AE5D1B1A5AA64687651E9E27EDC3EF95E1FD55EB836A9BD74EC264F7496245C217899DBFE70F12C7CC2174031A7DCC51FE8B06BE0B508B59C793DBB21043850777B410921EDCCC0062926E418EAF76EA67AF847A2B58915019B72B99F71B92969D6385A780DD2A488124326E15D3E886AFA93A19CB39FF35123C1BF6524B5CB24A5FDF21A8E8F7B905BD18305DF6BD9DBFCBFCC605F0E8A1A2A6B9F493CC2AF2E13F70CA68C780E62C8BB394E530C68FD59D9B73348814049D80154C793C597775734A42991CD035CFD97460BB91A629845936B1B61F3AAABB69A0063B08A02574B13D61A89BB0156F3FAE006017B8BB0184EFDB7082AD2CFCFB68980CA14CA0E87F77124746FCBA4EA29EDF90548E56FC55C3C2156B35EE47AB9C280B9DCFEAB47A04ECAB3E457DA21718C626CD8B21C92962654D97E9CE10C638FB02481481EDD01572DCCBF327FB8A1E978B8B0EE456F718FEE6E5B6439B8E379DF485E62D2B5DAE427001D2E5BB831AE1CC176164937A966C509A616E853FE729DB6A536C069053505C195E423688DB35726506A0A60716A920C6EC7E9785C836248123327D9B3E7FD36F3CF5C774BA1D3239CD5296897E961242980468A2248A48A066354B2BF33F8ECEC1CBBC087EA051832585E67DC6D70CA83847A255B9C533D50CDB75676F0E38AFBA14A428A85D9E4FC3731706DE21989E96822A858BCA9B7948B6DF5F1263C832D247425E5A2E586B37F998DDFB7201007297DDFBCB177F9DC7D80773784E0A0F8F16F6FAF3C0BC35849DFC6ECC6197E170CBB52CB1CFFD9C142D9F9B2EE6975E6242BE633109986EF09CCB85D4BEE6E05B41A6077225182DD670B3589EA25B0068A31506FE06DB38DABDA44AC0EF7430475F455ABED8C81DDEC6135979ACFE0488E8985F3C0754651AA462A256F2AA469EF4A68DDA352C7914195FCCFF3E80618316B86AB79311DEB59C4A8B665CBA8CEA44603C56304761EF2E181124BEFDF68E661CA669A55B8A2E9118C5976E8EBFB4BC5DBCB11CF542C22A11E4BD3B5413DA570816DA280C78318103BCA762728D2BF5EC282D22C25DA688173CD5E7FCC41AFBDA4FB199337F12EEB2D89B64E35216393A95D51EE468AD950B9D9FA8B840E2497D974E5B4B315FF2413A44D4DD0127B14F491285CBAB7E4B707663B38934299BD8CE7773BB1EF7FD4082CEF4763BCFC8AA37F185680A4633A8D611BE26FAD189AD1BD86979FEEB52C5CA7F26444F03DCA21917995763E96C46104889D9B41EA9AE2D0AC7F90B43FBEF282D04AF67C2D0CF36769D35351E36E555F10ECDD4CA2D079B08084653D6593754413AD71C4668974D6E6A9A3C045A0EBD49929B94D12DBD50CAB93C24D72F259AE2571BE40EF88F1618B59EAFDBCEC79CA01797DBFC2F6A6B2A08A2140242236B76CBD2178694181F48A49A0F7B428F2EE420F8B4F62C0058F8AB3B8813A24E2A9A6E6C332CFD39F20156CA1F9C6C44DB262C62880713FE2319A82EA9439F0C1FE0504D5799AF425E9B1E5824099E61D8A84FEDD83DDB3163C920A2F88638466574AEA92AD353B00E92BEAE8678D181AF4FA52338FDCBF0CEC9A426EF4C1D9F2F4161DEDA380A800DB01884B25139AD7794C2A97CB8FBFC74099A1849D7E47A9FA71765CB3888009F4CD59D79C2923E1C32D076E1F4106D19D88737D2A4AA0BA5CE96939F73F5A3CC4AC6BBB412C3CE7441D2F421580D16BB454DFA2E4358419816448F8A7C6F092E2B9134DD8679AD6BAEEF239222F6C2D4387EAA1751AD5";
    // let hex_data = include_str!("./qdec/test.hexqrc");
    // let dec_data = include_str!("./qdec/test.qrc");
    let hex_data = decode_hex(hex_data);
    let mut fast_time = std::time::Duration::MAX;
    let mut slow_time = std::time::Duration::ZERO;
    let mut all_time = std::time::Duration::ZERO;
    for _ in 0..10000 {
        let hex_data = hex_data.to_owned();
        let i = std::time::Instant::now();
        decrypt_qrc_raw(&mut hex_data.to_owned());
        let e = i.elapsed();
        if e < fast_time {
            fast_time = e;
        }
        if e > slow_time {
            slow_time = e;
        }
        all_time += e;
    }
    println!("Fastest decrypt time: {fast_time:?}");
    println!("Slowest decrypt time: {slow_time:?}");
    println!("Average decrypt time: {:?}", all_time / 10000);
    // assert_eq!(decrypted, dec_data);
}
